//! # MATLAB Parser
//!
//! A library to parse MATLAB code into a Rust-based Abstract Syntax Tree (AST).
//! This library provides the necessary data structures for representing the AST and
//! the parser logic to transform source code into this structure.

// Re-export the AST and parser modules to make them accessible to library users.
pub mod ast;
pub mod parser;

use ariadne::{sources, ColorGenerator, Label, Report, ReportKind, Source};
use chumsky::{span::SimpleSpan, Parser};
use std::path::Path;

struct Span(SimpleSpan);

impl ariadne::Span for Span{
    type SourceId=();

    fn source(&self) -> &Self::SourceId {
        return &();
    }

    fn start(&self) -> usize {
        return self.0.start
    }

    fn end(&self) -> usize {
        return self.0.end
    }
}

/// Parses MATLAB source code into an AST `Program`.
///
/// # Arguments
///
/// * `source_code` - A string slice that holds the MATLAB code to be parsed.
///
/// # Returns
///
/// A `Result` which is:
/// - `Ok(Program)` containing the root of the AST if parsing is successful.
/// - `Err(String)` containing a formatted error report if parsing fails.
pub fn parse_matlab_code(source_code: &str) -> Result<ast::Program, String> {
    let result= ast::parser::program_parser().parse(source_code).into_result();

    match result {
        Ok(program)=>Ok(program),
        Err(errors)=>{
        // Generate a formatted error report.
        let mut error_report = String::new();
        let mut colors = ColorGenerator::new();

        for error in errors {
            let mut report_builder = Report::build(ReportKind::Error,("builtin".to_string(), error.span().into_range()))
                .with_message(error.to_string())
                .with_label(Label::new(("builtin".to_string(), error.span().into_range())).with_color(colors.next()).with_message(error.to_string()));

            let mut buffer = Vec::new();
            report_builder
                .finish()
                .print(sources([("builtin".to_string(), source_code.clone())]))
                .unwrap();
            error_report.push_str(&String::from_utf8_lossy(&buffer));
        }
        Err(error_report)
        }
    }
}

/// Parses a MATLAB file from the given path.
///
/// # Arguments
///
/// * `file_path` - A reference to a `Path` for the MATLAB file.
///
/// # Returns
///
/// A `Result` which is:
/// - `Ok(Program)` containing the root of the AST if parsing is successful.
/// - `Err(String)` containing a formatted error report or an I/O error message.
pub fn parse_matlab_file(file_path: &Path) -> Result<ast::Program, String> {
    match std::fs::read_to_string(file_path) {
        Ok(content) => parse_matlab_code(&content),
        Err(e) => Err(format!("Error reading file: {}", e)),
    }
}
